// 闭包也叫匿名函数，闭包有以下几个特点 :
// .可以像函数一样被调用 。
// ·可以捕获上下文环境中的自由变量。
// .可以自动推断输入和返回的类型。
// 闭包也可以作为函数的参数和返回值

pub(in crate) fn start() {
    let out = 42;
    // fn add(i :i32, j :i32) -> i32 {
    //     i + j + out // 这里会编译失败，因为函数不能捕获上下文的中变量
    // }

    // 这是函数
    fn add(i: i32, j: i32) -> i32 {
        i + j
    }

    // 带有类型注解的闭包
    let closure_annotated = |i: i32, j: i32| -> i32 { i + j + out };
    let closure_inferred = |i, j| i + j + out;

    let i = 1;
    let j = 2;
    assert_eq!(3, add(i, j));
    assert_eq!(45, closure_annotated(i, j));
    assert_eq!(45, closure_inferred(i, j));

    // 闭包和函数最大的区别是，闭包可以捕获外部的变量，函数不可以

    assert_eq!(closure_math(|| j + i), 3);
    assert_eq!(closure_math(|| j + i + i), 4);
    let closure_impl = closure_impl();
    assert_eq!(4, closure_impl(2));
}

// 闭包作为参数
fn closure_math<F: Fn() -> i32>(op: F) -> i32 {
    op()
}

// 闭包作为返回值
fn closure_impl() -> impl Fn(i32) -> i32 {
    let i = 2;
    move |j| j * i
}
